package net.melon.sso.inst.ssh.manager;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.inject.Named;
import javax.inject.Singleton;

import net.esj.basic.dao.querybuilder.QueryBuilder;
import net.esj.basic.exception.MelonException;
import net.esj.basic.exception.MelonRuntimeException;
import net.esj.basic.pojo.op.AuthFunction;
import net.esj.basic.service.impl.DefaultServiceImpl;
import net.esj.basic.utils.Assert;
import net.esj.basic.utils.DateUtils;
import net.esj.basic.utils.SecurityUtils;
import net.esj.basic.utils.StringUtils;
import net.esj.basic.utils.Validators;
import net.melon.sso.SSOConstants;
import net.melon.sso.pojo.Config;
import net.melon.sso.pojo.Member;
import net.melon.sso.pojo.MemberExtra;
import net.melon.sso.pojo.MemberType;
import net.melon.sso.pojo.WebSite;
import net.melon.sso.provider.MemberAuthProvider;
import net.melon.sso.service.SSOManage;
import net.melon.sso.service.SSOService;

import org.springframework.transaction.annotation.Transactional;

@Transactional
@Singleton
@Named("sso.ssoManage")
public class SSOManageImpl extends DefaultServiceImpl implements SSOManage,SSOConstants {
	
	@Resource
	private SSOService ssoService;
	
	@Resource
	private MemberAuthProvider memberAuthProvider;

	@Override
	public void deleteMemberType(String id) {
		QueryBuilder<Member> qb = createQueryBuilder(Member.class);
		qb.eq("type.id", id);
		int c = queryCountByQueryBuilder(qb);
		if(c>0){
			throw new MelonRuntimeException("该类型已被使用，不能删除");
		}
		MemberType type = new MemberType();
		type.setId(id);
		delete(type);
	}

	@Override
	public List<MemberType> listMemberType() {
		return findAll(MemberType.class);
	}
	
	@Override
	public List<Config> getExtras() {
		if(!isAutoExtra()){
			return Collections.EMPTY_LIST;
		}
		Map<String,Config> map = ssoService.loadConfig(false);
		List<Config> retal = new ArrayList<Config>();
		for(Map.Entry<String,Config> entry:map.entrySet()){
			if(entry.getKey().startsWith(CONFIG_SSO_MEMBER_EXTRA_NAME_PREKEY)
					&& entry.getValue().isUsable()){
				retal.add(entry.getValue());
			}
		}
		return retal;
	}
	
	@Override
	public boolean isAutoExtra(){
		String v = SSOService.getConfigByKey(CONFIG_SSO_MEMBER_AUTO_EXTRA_VALUE).getValue();
		if(!StringUtils.hasText(v)){
			v = Boolean.FALSE.toString();
		}
		return Boolean.valueOf(v);
	}
	
	@Override
	public Member saveMember(Member member) throws MelonException{
		if(ssoService.checkMemberUnique(member.getMobile())){
			save(member);
		}else{
			throw new MelonException("err.unique.exists");
		}
		return member;
	}
	
	@Override
	public Member updateMember(Member member) throws MelonException{
		Member persist = get(member.getId(), Member.class);
		persist.setMobile(member.getMobile());
		persist.setRealname(member.getRealname());
		persist.setType(member.getType());
		persist.setState(member.getState());
		update(persist);
		return member;
	}
	
	@Override
	public Member getMember(String id) {
		return getMember(id, false);
	}
	
	@Override
	public Member getMember(String id,boolean withExtra) {
		Assert.notNull(id);
		Member member = get(id, Member.class);
		return member;
	}
	
	@Override
	public List<MemberExtra> listMemberExtra(String memberId) {
		QueryBuilder<MemberExtra> qb = createQueryBuilder(MemberExtra.class);
		qb.eq("member.id", memberId);
		List<MemberExtra> list = queryListByQueryBuilder(qb);
		for(MemberExtra member:list){
			if(member.getSite()!=null){
				member.setSite(ssoService.getWebSite(member.getSite().getId()));
			}
		}
		return list;
	}
	
	@Override
	public void addExtra(String memberId, String name, String value,
			WebSite webSite) {
		MemberExtra me = findExtraByName(memberId, name);
		if(me==null){
			Config config = ssoService.getConfigByKey(name);
			me = new MemberExtra();
			if(config.isGroup()){
				name = getConfigGroupName(config);
			}
			me.setValue(value);
			Member member = new Member();
			member.setId(memberId);
			me.setMember(member);
			me.setName(name);
			me.setSite(webSite);
			save(me);
		}else{
			me.setValue(value);
			update(me);
		}
	}
	
	private String getConfigGroupName(Config config) {
		int count = getMaxBrotherCount(config);
		if(count==1){
			return config.getKey();
		}else{
			return config.getKey() + Config.GROUP_POSTFIX + count;
		}
	}

	private int getMaxBrotherCount(Config config) {
		List<MemberExtra> list = getMemberExtraListByConfigKey(config);
		if(Validators.isEmpty(list)){
			return 1;
		}else{
			MemberExtra memberExtra = list.get(list.size() - 1);
			int count = Integer.valueOf(memberExtra.getValue().split(Config.GROUP_POSTFIX)[1]);
			return count + 1;
		}
		
	}

	protected MemberExtra findExtraByName(String memberId,String name){
		QueryBuilder<MemberExtra> qb =createQueryBuilder(MemberExtra.class);
		qb.eq("member.id", memberId).eq("name", name);
		MemberExtra me = (MemberExtra) queryFirst(qb);
		return me;
	}

	@Override
	public boolean checkDeleteConfig(Config config) {
		if(Validators.isEmpty(getMemberExtraListByConfigKey(config))){
			return true;
		}else{
			return false;
		}
	}
	
	@Override
	public List<MemberExtra> getMemberExtraListByConfigKey(Config config){
		QueryBuilder<MemberExtra> qb = createQueryBuilder(MemberExtra.class);
		if(config.isGroup()){
			qb.like("value", config.getKey()+Config.GROUP_POSTFIX+"%");
		}else{
			qb.eq("value", config.getKey());
		}
		qb.OrderByAsc("value");
		return queryListByQueryBuilder(qb);
	}

	@Override
	public MemberType getMemberType(String id) {
		return get(id, MemberType.class);
	}

	@Override
	public Collection<AuthFunction> authFunctions(Member member) {
		if(memberAuthProvider!=null){
			return memberAuthProvider.authFunctions(member);
		}
		return Collections.EMPTY_LIST;
	}

	@Override
	public MemberType defaultRegisityMemberType() {
		String type = SSOService.getConfigByKey(CONFIG_SSO_MEMBER_DEFAULT_REGISTRY_TYPE).getValue();
		if(StringUtils.hasText(type)){
			return getMemberType(type);
		}
		return null;
	}

	@Override
	public void editPass(Member member, String pwd) {
		member.setPassword(SecurityUtils.getMD5(pwd));
		update(member);
		ssoService.logout();
	}
}
